/**
* 版权声明：厦门睿商网络科技有限公司 版权所有 违者必究
* 日    期：2020-05-25
*/
package com.rzico.order.service;

import com.rzico.account.entity.Payable;
import com.rzico.base.BaseMapper;
import com.rzico.base.impl.BaseServiceImpl;
import com.rzico.basics.entity.Enterprise;
import com.rzico.basics.service.EnterpriseService;
import com.rzico.core.entity.SysUser;
import com.rzico.core.service.SysSequenceService;
import com.rzico.core.service.SysUserService;
import com.rzico.exception.CustomException;
import com.rzico.order.entity.*;
import com.rzico.order.enumx.*;
import com.rzico.order.mapper.AllocateMapper;
import com.rzico.util.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/**
 * <pre>
 * 调拨单业务类
 * </pre>
 *
 * @author Rzico Boot
 * @version 1.0
 */
@Service
public class AllocateService extends BaseServiceImpl<Allocate, String> {

    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AllocateMapper allocateMapper;

    @Autowired
    private AllocateItemService allocateItemService;

    @Autowired
    private EnterpriseService enterpriseService;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private SysSequenceService sysSequenceService;

    @Autowired
    private WarehouseStockService warehouseStockService;

    @Autowired
    private WarehouseService warehouseService;

    @Autowired
    private WarehouseItemService warehouseItemService;
    @Override
    public BaseMapper<Allocate, String> getMapper() {
        return allocateMapper;
    }


    @Transactional(rollbackFor = Exception.class)
    public int insertOrder(Allocate allocate){
        String allocateId = sysSequenceService.generate("order");
        Enterprise enterprise = enterpriseService.getCurrent();
        allocate.setEnterpriseId(enterprise.getId());
        SysUser sysUser = sysUserService.getCurrent();

        if (null == allocate.getOrderDate()){
            allocate.setOrderDate(DateUtils.truncate(new Date(),Calendar.DATE));
        }
        allocate.setSn(allocateId);
        allocate.setOrderStatus(AllocateStatusEnum.ALLOCATE_STATUS_UNCONFIRM.getId());
        allocate.setShippingStatus(AllocateShippingStatusEnum.ALLOCATE_SHIPPING_WAIT_OUT.getId());
        return this.insertUseGeneratedKeys(allocate);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertUseGeneratedKeys(Allocate allocate) {
        //调拨日
        allocate.setOrderDate(DateUtils.truncate(allocate.getOrderDate(), Calendar.DATE));
        int affectCount = super.insertUseGeneratedKeys(allocate);
        if (affectCount > 0){
            for (AllocateItem allocateItem : allocate.getItemList()){
                allocateItem.setAllocateId(allocate.getId());
            }
            allocateItemService.insertUseGeneratedKeyList(allocate.getItemList());
        }
        return affectCount;
    }

    @Transactional(rollbackFor = Exception.class)
    public int update(Allocate allocate){
        //不可编辑字段
        allocate.setEnterpriseId(null);
        allocate.setOfficeId(null);
        allocate.setOrderStatus(null);
        allocate.setShippingStatus(null);

        int affectCount = super.updateByPrimaryKeySelective(allocate);
        if (affectCount > 0){
            if (null != allocate.getItemList() && allocate.getItemList().size() > 0){
                for (AllocateItem allocateItem : allocate.getItemList()){
                    logger.info(allocateItem.getName() +"----"+ allocateItem.getQuantity());
                    allocateItemService.updateByPrimaryKeySelective(allocateItem);
                }
            }
        }
        return affectCount;
    }

    /**
     *  确认调拨单
     * @param id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public int confirm(Long id) {
        Allocate allocate = selectByPrimaryKey(id);
        if (null == allocate) {
            throw new CustomException("调拨单不存在");
        }
        allocate.setOrderStatus(AllocateStatusEnum.ALLOCATE_STATUS_CONFIRM.getId());
        return super.updateByPrimaryKey(allocate);
    }


    /**
     * 调拨出库
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public int allocateOut(Long id, List<AllocateItem> itemList){
        //1、检查销售订单是否存在
        Allocate allocate = selectByPrimaryKey(id);
        if (null == allocate){
            throw new CustomException("未查找到调拨单");
        }
        if (!allocate.getOrderStatus().equals(AllocateStatusEnum.ALLOCATE_STATUS_CONFIRM.getId())){
            throw new CustomException("不可发货");
        }

        //2、检查发货数量，并封装需要保存的allocateItemList
       /* String errMsg = "";
        List<AllocateItem> targetList = new ArrayList<>();
        for (AllocateItem paramItem : itemList){
            AllocateItem target = allocateItemService.selectByPrimaryKey(paramItem.getId());
            //可发货数量
            BigDecimal canShippingQuantity = target.getQuantity().subtract(target.getShippedQuantity());
            //可发货数量与前端传过来的发货数量对比
            int result = canShippingQuantity.compareTo(paramItem.getShippedQuantity());
            if (result < 0){
                errMsg = "发货数量大于可发货数量";
                break;
            }
            BigDecimal shippingQuantity = target.getShippedQuantity().add(paramItem.getShippedQuantity());
            target.setShippedQuantity(shippingQuantity);
            targetList.add(target);
        }
        if (StringUtils.isNotEmpty(errMsg)){
            throw new CustomException(errMsg);
        }*/
        //3、更新出入库状态“已出库”
        allocate.setShippingStatus(AllocateShippingStatusEnum.ALLOCATE_SHIPPING_HAS_OUT.getId());
        int affectCount = updateByPrimaryKeySelective(allocate);
        if (affectCount > 0){
            for (AllocateItem target : itemList){
                //4、更新商品的发货数量
                target.setShippedQuantity(target.getQuantity());
                allocateItemService.updateByPrimaryKeySelective(target);
            }

            //5、生成出库单
            allocate.setItemList(itemList);
            String sn = sysSequenceService.generate("warehouse");
            this.insertWarehouse(allocate, WarehouseTypeEnum.WAREHOUSE_TYPE_ALLOCATE_OUT.getId(),sn, allocate.getSn());
        }
        return affectCount;
    }


    /**
     * 调拨入库
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public int allocateIn(Long id, List<AllocateItem> itemList){
        //1、检查销售订单是否存在
        Allocate allocate = selectByPrimaryKey(id);
        if (null == allocate){
            throw new CustomException("未查找到调拨单");
        }
        if (!allocate.getOrderStatus().equals(AllocateStatusEnum.ALLOCATE_STATUS_CONFIRM.getId())){
            throw new CustomException("不可发货");
        }
        if (!allocate.getShippingStatus().equals(AllocateShippingStatusEnum.ALLOCATE_SHIPPING_HAS_OUT.getId())){
            throw new CustomException("尚未调拨出库,不可入库");
        }

        //3、更新出入库状态“已入库”,订单状态"已完成"
        allocate.setShippingStatus(AllocateShippingStatusEnum.ALLOCATE_SHIPPING_HAS_IN.getId());
        allocate.setOrderStatus(AllocateStatusEnum.ALLOCATE_STATUS_COMPLETE.getId());
        int affectCount = updateByPrimaryKeySelective(allocate);
        if (affectCount > 0){
            for (AllocateItem target : itemList){
                //4、更新商品的入库数量
                target.setReceiviedQuantity(target.getQuantity());
                allocateItemService.updateByPrimaryKeySelective(target);
            }

            //5、生成入库单
            allocate.setItemList(itemList);
            String sn = sysSequenceService.generate("warehouse");
            this.insertWarehouse(allocate, WarehouseTypeEnum.WAREHOUSE_TYPE_ALLOCATE_IN.getId(), sn, allocate.getSn());
        }
        return affectCount;
    }

    @Transactional(rollbackFor = Exception.class)
    public int cancel(Long id){
        int affectCount = 0;
        //1、判断单据是否存在
        Allocate allocate = selectByPrimaryKey(id);
        if (null == allocate){
            throw new CustomException("调拨单不存在");
        }
        Integer orderStatus = allocate.getOrderStatus();
        //2、非已确认，不可作废
        if (allocate.getOrderStatus().equals(AllocateStatusEnum.ALLOCATE_STATUS_COMPLETE.getId())){
            throw new CustomException("调拨单已完成，不可作废");
        }
        //3、更新单据状态，并处理库存数据
        allocate.setOrderStatus(AllocateStatusEnum.ALLOCATE_STATUS_CANCLE.getId());
        affectCount = super.updateByPrimaryKeySelective(allocate);
        if (affectCount > 0){
            //已确认，需要还原已出库的库存
            if (orderStatus.equals(AllocateStatusEnum.ALLOCATE_STATUS_CONFIRM.getId())){
                Warehouse params = new Warehouse();
                params.setOrderId(allocate.getId());
                params.setWarehouseType(WarehouseTypeEnum.WAREHOUSE_TYPE_ALLOCATE_OUT.getId());
                List<Warehouse> warehouseList = warehouseService.select(params);
                if (null != warehouseList && warehouseList.size() >0){
                    for (Warehouse warehouse : warehouseList){
                        //更新出库单从“已出库”到“已取消”
                        warehouse.setStatus(WarehouseStatusEnum.WAREHOUSE_STATUS_CANCEL.getId());
                        warehouseService.updateByPrimaryKeySelective(warehouse);
                        //回滚出库单的库存
                        WarehouseItem wareItem = new WarehouseItem();
                        wareItem.setWarehouseId(warehouse.getId());
                        List<WarehouseItem> warehouseItemList = warehouseItemService.select(wareItem);
                        for (WarehouseItem warehouseItem : warehouseItemList){
                            warehouseStockService.afterCancelCompletion(warehouse.getWarehouseType(), warehouseItem);
                            warehouseStockService.preCancelHandle(warehouse.getWarehouseType(), warehouseItem);
                        }
                    }
                }else {
                    throw new CustomException("采购单尚未查找到对应的出入库单，请核对");
                }
            }
        }
        return affectCount;
    }

    /**
     * 生成出入库
     * @param allocate
     */
    @Transactional(rollbackFor = Exception.class)
    public void insertWarehouse(Allocate allocate, Integer warehouseType,String sn, String orderSn){
        SysUser sysUser = sysUserService.getCurrent();
        Warehouse warehouse = new Warehouse();
        warehouse.setSn(sn);
        warehouse.setStatus(0);
/*        //调入单位
        warehouse.setConsignee(allocate.getInShopName());
        //调出单位
        warehouse.setAddress(allocate.getOutShopName());*/
        warehouse.setWarehouseType(warehouseType);
        warehouse.setOrderId(allocate.getId());
        warehouse.setEnterpriseId(allocate.getEnterpriseId());
        if (warehouseType.equals(WarehouseTypeEnum.WAREHOUSE_TYPE_ALLOCATE_OUT.getId())){
            warehouse.setShopId(allocate.getOutShopId());
        }else{
            warehouse.setShopId(allocate.getInShopId());
        }

        warehouse.setDeleted(false);
        warehouse.setOfficeId(allocate.getOfficeId());
        warehouse.setOperatorId(sysUser.getId());
        warehouse.setSPrint(0);
        warehouse.setMemberId(allocate.getOutShopId());
        warehouse.setSupplierId(allocate.getOutShopId());
        warehouse.setOrderDate(DateUtils.truncate(new Date(),Calendar.DATE));
        warehouse.setTaxType(0);
        warehouse.setOrderSn(orderSn);
        //明细表数据
        List<WarehouseItem> itemsList = new ArrayList<>();
        for (AllocateItem allocateItem : allocate.getItemList()){
            WarehouseItem warehouseItem = new WarehouseItem();
            //调拨单的cost先填0
            warehouseItem.setCost(BigDecimal.ZERO);
            warehouseItem.setName(allocateItem.getName());
            warehouseItem.setPrice(allocateItem.getPrice());
            warehouseItem.setQuantity(allocateItem.getQuantity());
            warehouseItem.setSn(allocateItem.getSn());
            warehouseItem.setSpec(allocateItem.getSpec());
            warehouseItem.setProductId(allocateItem.getProductId());
            warehouseItem.setWarehouseId(warehouse.getId());
            warehouseItem.setDiscount(BigDecimal.ZERO);
            warehouseItem.setUnit(allocateItem.getUnit());
            //冗余存储
            warehouseItem.setShopId(warehouse.getShopId());
            warehouseItem.setEnterpriseId(warehouse.getEnterpriseId());
            warehouseItem.setTax(BigDecimal.ZERO);
            itemsList.add(warehouseItem);
        }
        warehouse.setItemList(itemsList);
        warehouse.setSubPrice(warehouse.calculateSubPrice());
        warehouse.setSubQuantity(warehouse.calculateSubQuantity());

        warehouseService.insertUseGeneratedKeys(warehouse);
        //自动确认
        warehouseService.confirm(warehouse.getId());
        //自动审核通过
        warehouseService.audit(warehouse.getId());
    }


    public int checkAndUpdateStatus(Long allocateId){
        int affectCount = 0;
        if (checkAllocate(allocateId)){
            Allocate allocate = new Allocate();
            allocate.setId(allocateId);
            allocate.setOrderStatus(AllocateStatusEnum.ALLOCATE_STATUS_COMPLETE.getId());
            affectCount = this.updateByPrimaryKeySelective(allocate);
        }
        return affectCount;
    }

    public Boolean checkAllocate(Long allocateId){
        Allocate allocate = selectByPrimaryKey(allocateId);
        if (null == allocate){
            throw new CustomException("调拨单据不存在");
        }
        Boolean hasIn = true;
        AllocateItem param = new AllocateItem();
        param.setAllocateId(allocate.getId());
        List<AllocateItem> list = allocateItemService.select(param);
        for (AllocateItem allocateItem : list){
            BigDecimal quantity = allocateItem.getQuantity();
            BigDecimal receiviedQuantity = allocateItem.getReceiviedQuantity();
            if (quantity.compareTo(receiviedQuantity) != 0){
                hasIn = false;
                break;
            }
        }
        return hasIn;
    }

    /**
     * 更新调拨单的入库数量
     * @param allocateId
     * @param warehouseId
     */
    public void updateAllocateReceiviedQuantity(Long allocateId, Long warehouseId){
        Allocate allocate = selectByPrimaryKey(allocateId);
        if (null == allocate){
            throw new CustomException("调拨单据不存在");
        }
        AllocateItem param = new AllocateItem();
        param.setAllocateId(allocate.getId());
        List<AllocateItem> list = allocateItemService.select(param);

        WarehouseItem itemParam = new WarehouseItem();
        itemParam.setWarehouseId(warehouseId);
        List<WarehouseItem> itemList = warehouseItemService.select(itemParam);

        for (AllocateItem allocateItem : list){
            for (WarehouseItem warehouseItem : itemList){
                if (allocateItem.getProductId().equals(warehouseItem.getProductId())){
                    BigDecimal receiviedQuantity = allocateItem.getReceiviedQuantity().add(warehouseItem.getQuantity());
                    allocateItem.setReceiviedQuantity(receiviedQuantity);
                    allocateItemService.updateByPrimaryKeySelective(allocateItem);
                    break;
                }
            }
        }
    }
}
